package com.zj.thread.selfFuture;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

public class FutureWithCallBack {


    public static void main(String[] args) {
//        testInvoke();
        testBlock();
        System.out.println("submit end");
    }

    static void testBlock(){
        Future<Integer> invoke = new FutureWithCallBack().block((String bb)->{
            System.out.println("task start");
            try {
                Thread.sleep(4000);
                int b=1/0;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return bb.length();
        },"aaaaaaaaaaaaaa");
        invoke.setCompetable(new Competable<Integer>() {
            @Override
            public void complete(Integer integer) {
                System.out.println("call back:"+integer);
            }

            @Override
            public void exception(Throwable th) {
                System.out.println("call back:"+th);
            }
        });
        System.out.println("submit start");
    }





    <T,R> Future<T> block(Callable<T,R> callable, R r){
        AtomicReference<T> result=new AtomicReference<>();
        AtomicBoolean state=new AtomicBoolean(false);
        Future<T> tBlockFuture = new BlockFuture<>(result, state);
        Thread t=new Thread(()->{
            try{
                T action = callable.action(r);
                result.set(action);
                state.set(true);
                if(tBlockFuture.getCompetable()!=null){
                    tBlockFuture.getCompetable().complete(action);
                }
            }catch (Exception e){
                if(tBlockFuture.getCompetable()!=null){
                    tBlockFuture.getCompetable().exception(e);
                }
            }

        });
        t.start();
        return tBlockFuture;
    }


    class BlockFuture<T> implements Future<T> {
        AtomicReference<T> result;
        AtomicBoolean state;
        Competable<T> competable;
        BlockFuture(AtomicReference<T> result,AtomicBoolean state){
            this.result=result;
            this.state=state;
        }

        @Override
        public T get() {
            while(!state.get()){
            }
            return result.get();
        }

        @Override
        public boolean isDone() {
            return state.get();
        }

        @Override
        public Competable<T> getCompetable() {
            return competable;
        }

        @Override
        public void setCompetable(Competable<T> com) {
            this.competable=com;
        }
    }

    interface Future<T> {
        T get();
        boolean isDone();
        Competable<T> getCompetable();
        void setCompetable(Competable<T> com);
        
    }

    interface Callable<T,R>{
        T action(R r);
    }

    interface Competable<T>{
        void complete(T t);
        void exception(Throwable th);
    }
}
